#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "MQTTClient.h"

#define ADDRESS "tcp://192.168.12.67:1883"
#define CLIENTID "b253ba38-daf6-4b37-984f-5d8fdc6a1cfa"
#define TOPIC_PULL "pull"
#define TOPIC_PUSH "topic_gateway"
#define PAYLOAD "Hello World!"
#define QOS 1
#define TIMEOUT 10000L

/**
 * @brief MQTT客户端和服务端之间传输数据的结构，只需要关注部分字段
 *  payload：消息负载，真正要传递的数据
 *  payloadlen：负载长度
 *  qos：服务质量，详见上文
 *  retained：对于发布者，这表明该消息不应由 MQTT 服务器保留
 *  
 */
static MQTTClient_message pubmsg = MQTTClient_message_initializer;

// MQTTClient_deliveryToken
// MQTT客户端的交付令牌，所谓令牌就是用于标识和追踪特定操作或事件的唯一标识符，
// 这里的交付令牌用于标识MQTT消息，当消息被发布时会返回一个交付令牌，用于告知客户端消息发布的结果
void delivered(void *context, MQTTClient_deliveryToken dt)
{
    printf("Message with token value %d delivery confirmed\n", dt);
}

// 这段代码是一个MQTT客户端的消息接收回调函数，用于处理从MQTT服务器接收到的消息。
int msgarrvd(void *context, char *topicName, int topicLen, MQTTClient_message *message)
{
    printf("Message arrived\n");
    printf("   topic: %s\n", topicName);
    printf("  message: %.*s\n", message->payloadlen, (char *)message->payload);
    // 释放消息和主题名称的内存
    MQTTClient_freeMessage(&message);
    MQTTClient_free(topicName);
    return 1;
}

void connlost(void *context, char *cause)
{
    printf("\nConnection lost\n");
    printf("   cause: %s\n", cause);
}

int main(int argc, char *argv[])
{
    // 指向MQTT客户端的句柄（可以操作某个对象的引用），成功调用MQTTClient_create()函数后可以得到一个有效的客户端句柄，
    // 可以用于连接、订阅、发布等客户端操作
    MQTTClient client;

    /**
     * @brief MQTT客户端连接选项，我们只需要关注其中的部分选项：
     *  connectTimeout：连接超时时间
     *  keepAliveInterval：保持连接的最长时间间隔
     *  cleansession：标志位，连接断开时是否清除会话信息
     */
    MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer;
    // MQTTClient_connectOptions_initializer
    // 这是一个宏，用于初始化MQTTClient_connectOptions结构体
    // 它将结构体的所有成员设置为默认值，确保结构体被正确初始化
    // 避免直接声明结构体时可能出现的未初始化问题

    int rc;

    // MQTTClient_create()函数用于创建一个MQTT客户端,成功后返回MQTTCLIENT_SUCCESS，值为0
    if ((rc = MQTTClient_create(&client,                     // MQTT客户端句柄
                                ADDRESS,                     // MQTT服务器地址
                                CLIENTID,                    // MQTT客户端ID
                                MQTTCLIENT_PERSISTENCE_NONE, // MQTT客户端持久化策略
                                NULL                         // MQTT客户端回调上下文
                                )) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to create client, return code %d\n", rc);
        rc = EXIT_FAILURE;
        goto exit;
    }

    // MQTTClient_setCallbacks()函数用于设置MQTT客户端的回调函数，这些回调函数将在MQTT客户端的不同事件发生时被调用
    if ((rc = MQTTClient_setCallbacks(client, NULL, // MQTT客户端回调上下文
                                      connlost,     // MQTT客户端连接丢失回调函数
                                      msgarrvd,     // MQTT客户端消息到达回调函数
                                      delivered     // MQTT客户端消息交付确认回调函数
                                      )) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to set callbacks, return code %d\n", rc);
        rc = EXIT_FAILURE;
        goto destroy_exit;
    }

    // MQTTClient_connect()函数用于连接到MQTT服务器，成功后返回MQTTCLIENT_SUCCESS，值为0
    if ((rc = MQTTClient_connect(client, &conn_opts)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to connect, return code %d\n", rc);
        rc = EXIT_FAILURE;
        goto destroy_exit;
    }

    printf("Subscribing to topic %s\nfor client %s using QoS%d\n\n"
           "Press Q<Enter> to quit\n\n",
           TOPIC_PULL, CLIENTID, QOS);

    // MQTTClient_subscribe()函数用于订阅MQTT主题，成功后返回MQTTCLIENT_SUCCESS，值为0
    if ((rc = MQTTClient_subscribe(client, TOPIC_PULL, QOS)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to subscribe, return code %d\n", rc);
        rc = EXIT_FAILURE;
    }
    else
    {
        // 订阅成功了程序会一直活着
        // 用于从标准输入（通常是键盘）读取字符，直到用户输入 'Q' 或 'q' 为止
        int ch;
        do
        {
            ch = getchar();
        } while (ch != 'Q' && ch != 'q');

        // MQTTClient_unsubscribe()函数用于取消订阅MQTT主题，成功后返回MQTTCLIENT_SUCCESS，值为0
        if ((rc = MQTTClient_unsubscribe(client, TOPIC_PULL)) != MQTTCLIENT_SUCCESS)
        {
            printf("Failed to unsubscribe, return code %d\n", rc);
            rc = EXIT_FAILURE;
        }
    }

    pubmsg.payload = PAYLOAD;// 消息负载
    pubmsg.payloadlen = (int)strlen(PAYLOAD);// 消息负载长度
    pubmsg.qos = QOS;// 消息服务质量

    // MQTTClient_publishMessage()函数用于发布MQTT消息，成功后返回 MQTTCLIENT_SUCCESS，值为0
    if ((rc = MQTTClient_publishMessage(client, TOPIC_PUSH, &pubmsg, NULL)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to publish message, return code %d\n", rc);
        rc = EXIT_FAILURE;
    }

    // MQTTClient_disconnect()函数用于断开与MQTT服务器的连接，成功后返回MQTTCLIENT_SUCCESS，值为0
    if ((rc = MQTTClient_disconnect(client, 10000)) != MQTTCLIENT_SUCCESS)
    {
        printf("Failed to disconnect, return code %d\n", rc);
        rc = EXIT_FAILURE;
    }
    return rc;
destroy_exit:
    MQTTClient_destroy(&client);
exit:
    return rc;
}